package main

import (
	"fmt"
	"encoding/xml"
	"bufio"
	"os"
	"io"
)
/*
解析超大 xml 文件
https://studygolang.com/static/pkgdoc/pkg/encoding_xml.htm
*/
// 定义结构体映射xml结构
type SConfig struct {
	XMLName  xml.Name `xml:"config"` // 指定最外层的标签为config
	SmtpServer string `xml:"smtpServer"` // 读取smtpServer配置项，并将结果保存到SmtpServer变量中
	SmtpPort int `xml:"smtpPort"`
	Sender string `xml:"sender"`
	SenderPasswd string `xml:"senderPasswd"`
	Receivers SReceivers `xml:"receivers"` // 读取receivers标签下的内容，以结构方式获取
  }
   
  type SReceivers struct {
	Age int `xml:"age"`
	Flag string `xml:"flag,attr"` // 读取flag属性
	User []string `xml:"user"` // 读取user数组
	Script string `xml:"script"` // 读取 <![CDATA[ xxx ]]> 数据
  }

func readXml(path string) {
	file, errOpen := os.Open(path) // 打开文件
	if errOpen != nil {
		fmt.Println("打开文件异常！", errOpen)
		return
	}

	defer file.Close() // 关闭文件

	// 创建带缓存的 Reader
	reader := bufio.NewReader(file)

	decoder := xml.NewDecoder(reader)

	// var text bool
	for t, err := decoder.Token(); err == nil || err == io.EOF; t, err = decoder.Token() {
		switch token := t.(type) {
			case xml.StartElement:
				name := token.Name.Local
				fmt.Println(name)
				if name == "config" {
					// text = true
					// 解析 config 
					var sConfig = SConfig{}
					configErr := decoder.DecodeElement(&sConfig, &token)
					if configErr != nil {
						fmt.Println("解析错误：")
						fmt.Println(configErr)
					} else {
						fmt.Println(sConfig)
					}
					return
				}
			// case xml.EndElement:
			// 	text = false
			// case xml.CharData:
			// 	if text {
			// 		// fmt.Println("CharData")
			// 		// fmt.Printf("%T\n", token)
			// 		// fmt.Println([]byte(token))
			// 		// content := string([]byte(token))
			// 		// fmt.Println(content)
			// 	}
			// default:
			// 	// fmt.Printf("%T\n", token)
			// 	fmt.Println("default")
			// 	return
		}
	}
}

func main() {
	readXml("demo.xml")
} 